﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Configuration;
using System.IO;
using System.Net;
using System.Runtime.Serialization.Json;
using System.Text;
using Dogshow.Model;
using Dogshow.Win.Helpers;
using Dogshow.Win.Models;
using Dogshow.Win.RepoService;
using System.Linq;
using Kinolog = Dogshow.Model.Kinolog;
using Pas = Dogshow.Model.Pas;
using RasaPsa = Dogshow.Model.RasaPsa;
using Dogshow.Model.Extensions;
using KinoloskoDrustvo = Dogshow.Model.KinoloskoDrustvo;
using Mesto = Dogshow.Model.Mesto;

namespace Dogshow.Win.DataAccess
{
    public class WebDataService : IDataService
    {
        public readonly static string ServiceAddress = ConfigurationManager.AppSettings["serviceAddress"] + "/Json/";

        public IEnumerable<RasaPsa> VratiRasePasa()
        {
            return Get<RasaPsa[]>("VratiSveRasePasa");
        }

        public void Sacuvaj(IEnumerable<RasaPsa> rasePasa)
        {
            var changed = rasePasa.Where(x => x.Status != Status.Unchanged).Select(x => new RasaPsa { Id = x.Id, NazivRase = x.NazivRase }).ToArray();
            if (changed.Count() > 0)
            {
                Send("SacuvajRasePasa", changed);
            }
        }

        public void Sacuvaj(IEnumerable<Kinolog> kinolozi)
        {
            var changed = kinolozi.Where(x => x.Status != Status.Unchanged).Select(x => new Model.Kinolog { Id = x.Id, ImeIPrezime = x.ImeIPrezime, Telefon = x.Telefon, Adresa = x.Adresa, Mesto = x.Mesto, VrstaKinologa = x.VrstaKinologa}).ToArray();
            if (changed.Count() > 0)
            {
                Send("SacuvajKinologe", changed);
            }
        }

        public IList<Kinolog> VratiSudije()
        {
            return Get<IList<Kinolog>>("VratiKinologe/" + (int)VrstaKinologa.Sudija);
        }

        public IEnumerable<FciGrupa> VratiFciGrupe()
        {
            return Get<FciGrupa[]>("VratiSveFciGrupe");
        }

        public IEnumerable<InfoOPsu> VratInfoOPsima()
        {
            return Get<InfoOPsu[]>("VratiInfoOPsima");
        }

        public bool PostojiPas(string brojRodovnika, int idPsa)
        {
            if (String.IsNullOrEmpty(brojRodovnika)) return false;
            brojRodovnika = brojRodovnika.Replace('/', '|');
            return Get<bool>("PostojiPas/" + brojRodovnika + "/" + idPsa);
        }

        public Pas VratiPsaPoBrojuRodovnika(string brojRodovnika)
        {
            if (String.IsNullOrEmpty(brojRodovnika)) return null;
            brojRodovnika = brojRodovnika.Replace('/', '|');
            return Get<Pas>("VratiPsaPoBrojuRodovnika/" + brojRodovnika);
        }

        public void Sacuvaj(Models.Pas pas)
        {
            using (var svc = new RepoServicesClient())
            {
                var response = svc.SacuvajPsa(ModelMapper.Map(pas));
                if (response.HasErrors) throw new Exception(response.Error);
            }
        }

        public Pas VratiPsaPoId(int id)
        {
            return Get<Pas>("VratiPsa/" + id);
        }

        public IEnumerable<Titula> VratiTitule()
        {
            return Get<IEnumerable<Titula>>("VratiTitule");
        }

        public IEnumerable<Kinolog> VratiKinologaSaImenom(string imeIliId)
        {
            return Get<IEnumerable<Kinolog>>("VratiKinologaSaImenom/" + imeIliId);
        }

        public IEnumerable<Pas> PretraziPse(KriterijumPretragePasa kriterijum)
        {
            var parameters = new Dictionary<string, object>();
            var ime = kriterijum.ImePsa.TrimAndNull();

            if (ime != null)
            {
                parameters.Add("ime", ime);
            }
            if (kriterijum.IdRasePsa.HasValue)
            {
                parameters.Add("rasa", kriterijum.IdRasePsa);
            }
            if (kriterijum.IdFciGrupe.HasValue)
            {
                parameters.Add("fci", kriterijum.IdFciGrupe);
            }
            if (kriterijum.Vlasnik != null)
            {
                parameters.Add("vlasnik", kriterijum.Vlasnik.Id);
            }
            if (kriterijum.Odgajivac != null)
            {
                parameters.Add("odgajivac", kriterijum.Odgajivac.Id);
            }
            
            return Get<IEnumerable<Pas>>("PretraziPse" + QueryBuilder.CreateQueryString(parameters));
        }

        public IEnumerable<string> VratiMesta()
        {
            return Get<IEnumerable<string>>("VratiMesta");
        }

        public IEnumerable<Mesto> VratiMesta1()
        {
            return Get<IEnumerable<Mesto>>("VratiMesta1");
        }

        public IList<KinoloskoDrustvo> VratiKinoloskaDrustva()
        {
            return Get<IList<KinoloskoDrustvo>>("VratiKinoloskaDrustva");
        }

        public void Sacuvaj(KinoloskoDrustvo kinoloskoDrustvo)
        {
            Send("SacuvajKinoloskoDrustvo", kinoloskoDrustvo);
        }

        public void Sacuvaj(Mesto mesto)
        {
            Send("SacuvajMesto", mesto);
        }

        public IList<Kinolog> VratiSveKinologe()
        {
            return Get<IList<Kinolog>>("VratiKinologe");
        }

        private static WebClient GetClient()
        {
            return new WebClient(){BaseAddress = ServiceAddress};
        }

        private void Send<T>(string webMethod, T obj)
        {
            using (var client = GetClient())
            {
                client.Headers["Content-type"] = "application/json";
                client.UploadData(webMethod, Serialize(obj));
            }
        }

        private T Get<T>(string webMethod)
        {
            using (var client = GetClient())
            {
                var data = client.DownloadData(webMethod);
                if (data.Length == 0) throw new NotFoundException();
                return Deserialize<T>(data);
            }
        }

        private byte[] Serialize<T>(T obj)
        {
            var ser = new DataContractJsonSerializer(typeof(T));
            using (var ms = new MemoryStream())
            {
                ser.WriteObject(ms, obj);
                return ms.ToArray();
            }
        }

        private T Deserialize<T>(byte[] data)
        {
            var ser = new DataContractJsonSerializer(typeof(T));
            return (T)ser.ReadObject(new MemoryStream(data));
        }
    }
}